package com.xinyue.ext.reader.dao;

import java.util.ArrayList;
import java.util.List;

import org.dom4j.Element;

import com.xinyue.ext.data.FinderData;
import com.xinyue.ext.exception.FinderException;
import com.xinyue.ext.reader.ParamHolder;
import com.xinyue.ext.util.StringUtil;

public class SqlProcess extends DaoContext{
	//私有构造器
	private SqlProcess() {
	}
	//内部类
	private static class SingletonHolder{
        private static SqlProcess instance = new SqlProcess();  
    }
	/**
	 * 获得对象实例
	 */
	public static SqlProcess getInstance(ParamHolder holder) {
		DaoContext.holder = holder;
		return SingletonHolder.instance;
	}
	
	/**
	 * 读取sql标签数据
	 * param finder finder标签
	 */
	@SuppressWarnings("unchecked")
	@Override
	public void read(Element finder) throws FinderException {
		List<Element> sqs = finder.elements(sql_);
		
		//存在sql标签
		if(sqs != null && sqs.size() > 0) {
			List<FinderData> finders = new ArrayList<FinderData>();
			
			for (Element sql: sqs) {
				FinderData find = commonRead(sql);
				//返回值、强制类型转换、是否单个结果集处理
				sqlReturn(sql, find);
				//入参处理
				find.setParams(sqlParams(sql));
				//验证并整合SQL语句
				processSql(sql, find);
				
				finders.add(find);
			}
			
			holder.getDaoImptExt().add("org.hibernate.SQLQuery");
			holder.getEntity().getDao().setSqls(finders);
		}
	}
	
	
	/**仅SQL支持DTO参数
	 * 当DTO有值时，返回值类型只支持List，不是List时，默认为DTO单个对象
	 * @throws FinderException 
	 */
	private void sqlReturn(Element sql, FinderData find) throws FinderException {
		String type = sql.attributeValue(returnType_);
		if(StringUtil.isNull(type)) {
			throw new FinderException("sql标签未定义returnType属性或其值为空:" + type, holder.getException());
		}
		
		String dto = sql.attributeValue(dto_);
		/**
		 * 如果dto为null，返回其他hql支持类型
		 * 如果dto不为null,只能返回DTO或者List类型
		 */
		if(StringUtil.isNull(dto)) {
			//entity类型
			if(holder.getEntity().getClassName().equals(type)) {
				find.setConvert(true);
				find.setOnly(true);
				find.setReturnType(holder.getEntity().getClassName());
			}else if(LIST.equals(type)) {
				find.setWarning(true);
				find.setReturnType("List<" + holder.getEntity().getClassName() + ">");
			}else {
				//其他类型
				returnType(type, find);
			}
		}else {
			//dto类型
			holder.getDaoImpt().add(dto);
			if("DTO".equals(type)) {
				find.setConvert(true);
				find.setOnly(true);
				find.setReturnType(dto.substring(dto.lastIndexOf(".") + 1, dto.length()));
			}else if(LIST.equals(type)) {
				find.setWarning(true);
				find.setReturnType("List<" + dto.substring(dto.lastIndexOf(".") + 1, dto.length()) + ">");
			}else {
				throw new FinderException("sql标签设置了dto属性则其returnType只能是DTO或者List类型:" + type, holder.getException());
			}
		}
	}
	
	
	/**
	 * 入参处理
	 * @return
	 */
	private String sqlParams(Element sql) throws FinderException {
		String type = sql.attributeValue(paramType_); 
		
		if(StringUtil.isNull(type)) {
			throw new FinderException("sql标签没有定义paramType属性或者其值为空", holder.getException());
		}
		
		if(MAP.equals(type)) {
			holder.getDaoImpt().add("java.util.Map");
			return "Map<String, Object> map";
		}else {
			throw new FinderException("sql标签的paramType属性值非法:" + type, holder.getException());
		}
	}
	
	
	/**
	 * 对SQL语句进行预处理
	 * @throws FinderException 
	 */
	private void processSql(Element sql, FinderData find) throws FinderException {
		Element state = sql.element(sql_state_);
		if(state == null) {
			throw new FinderException("sql标签的sql_state未定义", holder.getException());
		}
		
		processQL(state, find);
	}
}
